# 减小DOM操作的性能开销
上一章我们讨论了渲染器是如何更新各种类型的 VNode 的,实际上,上一章所讲解的内容归属于完整的 Diff 算法之内,但并不包含核心的 Diff 算法。那什么才是核心的 Diff 算法呢?看下图:

我们曾在上一章中讲解子节点更新的时候见到过这张图,当时我们提到只有当新旧子节点的类型都是多个子节点时,核心 Diff 算法才派得上用场,并且当时我们采用了一种仅能实现目标但并不完美的算法:遍历旧的子节点,将其全部移除;再遍历新的子节点,将其全部添加,如下高亮代码所示:
function patchChildren(
prevChildFlags,
nextChildFlags,
prevChildren,
nextChildren,
container
) {
switch (prevChildFlags) {
// 省略...
// 旧的 children 中有多个子节点
default:
switch (nextChildFlags) {
case ChildrenFlags.SINGLE_VNODE:
// 省略...
case ChildrenFlags.NO_CHILDREN:
// 省略...
default:
// 新的 children 中有多个子节点
// 遍历旧的子节点,将其全部移除
for (let i = 0; i < prevChildren.length; i++) {
container.removeChild(prevChildren[i].el)
}
// 遍历新的子节点,将其全部添加
for (let i = 0; i < nextChildren.length; i++) {
mount(nextChildren[i], container)
}
break
}
break
}
}
@前端进阶之旅: 代码已经复制到剪贴板
为了便于表述,我们把这个算法称为:简单 Diff 算法。简单 Diff 算法虽然能够达到目的,但并非最佳处理方式。我们经常会遇到可排序的列表,假设我们有一个由 li 标签组成的列表:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
@前端进阶之旅: 代码已经复制到剪贴板
列表中的 li 标签是 ul 标签的子节点,我们可以使用下面的数组来表示 ul 标签的 children:
[
h('li', null, 1),
h('li', null, 2),
h(